/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package gride.plugin.shell;

import gride.GrideSettings;
import gride.events.EventListener;
import gride.events.GrideEvents;
import gride.plugin.GridePlugin;
import gride.gui.GUIManager;
import gride.plugin.executor.ExecutorGUIComponent;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;

/**
 *
 * @author lukasz
 */
public class GroovyShellPlugin extends GridePlugin
{
    // <editor-fold defaultstate="expanded" desc="Private Members">

    private ExecutorGUIComponent guiComponent;
    
    private Process groovyshProcess;

    private List<String> commandHistory;
    private int commandIndex;

    private Thread stdoutThread;
    private Thread stdinThread;
    private Thread stderrThread;

    // </editor-fold>


    // <editor-fold defaultstate="expanded" desc="Constructors">

    // </editor-fold>


    // <editor-fold defaultstate="expanded" desc="Getters/Setters">

    // </editor-fold>


    // <editor-fold defaultstate="expanded" desc="Public Methods">

    /**
     * 
     */
    @Override
    public void activate()
    {
        commandHistory = new ArrayList<String>();
        commandHistory.add("");
        commandIndex = 0;

        guiComponent = new ExecutorGUIComponent(false);
        guiComponent.setInputEnabled(true);

        guiComponent.getInputField().addKeyListener(new KeyAdapter()
        {
            @Override
            public void keyPressed(KeyEvent e)
            {
                int newIndex = commandIndex;

                if (e.getKeyCode() == KeyEvent.VK_UP)
                    newIndex--;
                else if (e.getKeyCode() == KeyEvent.VK_DOWN)
                    newIndex++;
                else
                    return;

                if (newIndex >= 0 && newIndex < commandHistory.size())
                {
                    // we're at the command that hasn't been executed yet
                    if (commandIndex == commandHistory.size() - 1)
                    {
                        // store the contents of the textfield
                        commandHistory.set(commandIndex,
                                        guiComponent.getInputField().getText());
                    }

                    // put the command from the history into the textfield
                    guiComponent.getInputField().setText(
                                                  commandHistory.get(newIndex));

                    commandIndex = newIndex;
                }
            }
        });


        guiManager.addComponent(GUIManager.BOTTOM_PANE, guiComponent,
                                "Groovy Shell");

        try
        {
            runGroovysh();

            // start a thread redirecting groovysh output to the gui component
            stdoutThread = new Thread()
            {
                @Override
                public void run()
                {
                    try
                    {                        
                        int chr;

                        // read a character at a time
                        while ((chr = groovyshProcess.getInputStream().read())
                                                                         != -1 )
                        {
                            // ignore characters that specify output color
                            // (not supported in our gui component)
                            if (chr == 27)
                            {
                                while (groovyshProcess.getInputStream().read()
                                                                        != 109);
                                continue;
                            }

                            // pass the read character to gui component
                            guiComponent.getOutputStream().write(chr);
                        }

                    }
                    catch (IOException e)
                    {
                        return;
                    }
                }

            };
            stdoutThread.start();
            
            // start a thread redirecting groovysh stderr to the gui component
            stderrThread = new Thread()
            {
                @Override
                public void run()
                {
                    try
                    {                        
                        int chr;

                        // read a character at a time
                        while ((chr = groovyshProcess.getErrorStream().read())
                                                                         != -1 )
                        {
                            // ignore characters that specify output color
                            // (not supported in our gui component)
                            if (chr == 27)
                            {
                                while (groovyshProcess.getErrorStream().read()
                                                                        != 109);
                                continue;
                            }

                            // pass the read character to gui component
                            guiComponent.getOutputStream().write(chr);
                        }

                    }
                    catch (IOException e)
                    {
                        return;
                    }
                }

            };
            stderrThread.start();


            // run a thread redirecting user input to the groovysh process
            stdinThread = new Thread()
            {
                @Override
                public void run()
                {
                    try
                    {
                        BufferedReader input = new BufferedReader(
                                               new InputStreamReader(
                                               guiComponent.getInputStream()));

                        String line = "";

                        while ((line = input.readLine()) != null)
                        {
                            // don't let the user exit groovysh
                            if (line.equals("exit") || line.equals("quit"))
                                continue;

                            // store the line in the command history
                            if (!line.trim().equals(""))
                            {
                                commandHistory.set(commandHistory.size() - 1,
                                                   line);
                                commandHistory.add("");
                                commandIndex = commandHistory.size() - 1;
                            }

                            for (char chr : line.toCharArray())
                                groovyshProcess.getOutputStream().write(chr);

                            groovyshProcess.getOutputStream().write('\n');
                            groovyshProcess.getOutputStream().flush();
                        }

                    }
                    catch (IOException ex)
                    {
                        return;
                    }
                }
            };
            stdinThread.start();


        }
        catch (IOException e)
        {
            System.out.println("Couldn't start groovysh plugin!");
            deactivate();
        }

        active = true;
    }

    /**
     *
     */
    @Override
    public void deactivate()
    {
        guiManager.removeComponent(guiComponent);
        eventManager.removeAllListenersFrom(this);

        if (groovyshProcess != null)
        {
            groovyshProcess.destroy();
            groovyshProcess = null;
        }

        if (stdoutThread != null && stdoutThread.isAlive())
            stdoutThread.stop();

        if (stderrThread != null && stderrThread.isAlive())
            stderrThread.stop();

        if (stdinThread != null && stdinThread.isAlive())
            stdinThread.stop();

        active = false;
    }

    private void runGroovysh() throws IOException
    {
        String command = GrideSettings.GROOVY_HOME_DIR + "/bin/groovysh";
        String[] envp = { "GROOVY_HOME=" + GrideSettings.GROOVY_HOME_DIR,
                          "JAVA_HOME=" + GrideSettings.JAVA_HOME_DIR };

        // run groovysh in a separate process
        if (projectManager.getCurrentProject() != null)
        {
            groovyshProcess = Runtime.getRuntime().exec(command, envp,
                            projectManager.getCurrentProject().getSourceDir());
        }
        else
        {
            groovyshProcess = Runtime.getRuntime().exec(command, envp);
        }
    }

    // </editor-fold>


    // <editor-fold defaultstate="expanded" desc="Private Methods">

    // </editor-fold>

}
